home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / DIZZY / SRC / ARROW.C next >
Text File  |  1990-12-29  |  12KB  |  512 lines

  1. /*
  2. >>    Dizzy 1.0    Arrow.c
  3. >>
  4. >>    A digital circuit simulator & design program for the X Window System
  5. >>
  6. >>    Copyright 1990 Juri Munkki, all rights reserved
  7. >>
  8. >>    Please read the included file called "DizzyDoc" for information on
  9. >>    what your rights are concerning this product.
  10. >>
  11. >>    This program contains that code that defines how the arrow tool acts
  12. >>    when the user clicks in the edit window.
  13. */
  14.  
  15. #include "dizzy.h"
  16.  
  17. Element *LastElem;        /*    Last element in top level            */
  18. int     ElemCount;        /*    Number of elements in top level.    */
  19.  
  20. /*
  21. >>    InvalLine invalides an area of the screen. That is, it forces
  22. >>    a redraw of the general area where a line was located.
  23. */
  24. void    InvalLine(x0,y0,x1,y1)
  25. int     x0,y0,x1,y1;
  26. {
  27.     Rect    inval;
  28.  
  29.     if(x0<x1)
  30.     {    inval.left = x0-8;
  31.         inval.right = x1+8;
  32.     }
  33.     else
  34.     {    inval.left = x1-8;
  35.         inval.right = x0+8;
  36.     }
  37.     if(y0<y1)
  38.     {    inval.top = y0-8;
  39.         inval.bottom = y1+8;
  40.     }
  41.     else
  42.     {    inval.top = y1-8;
  43.         inval.bottom = y0+8;
  44.     }
  45.     InvalRect(&inval);
  46. }
  47.  
  48. /*
  49. >>    While working on the X version of the program, I noticed that
  50. >>    in order to be fast enough, the program couldn't update the
  51. >>    whole display in cases when less was sufficient. I didn't
  52. >>    want to start creating regions for lines that needed to be
  53. >>    updated, so I decided to define a bounding box that would
  54. >>    be scrapped. TrashRect is this bounding box and the following
  55. >>    routines are used to manipulate it.
  56. */
  57. static    Rect    TrashRect;
  58.  
  59. void    SetTrashRect(r)
  60. Rect    *r;
  61. {
  62.     TrashRect= *r;
  63. }
  64.  
  65. void    ExpandTrash(x,y)
  66. int     x,y;
  67. {
  68.     if(x<TrashRect.left)        TrashRect.left=x;
  69.     else if(x>TrashRect.right)    TrashRect.right=x;
  70.  
  71.     if(y<TrashRect.top)         TrashRect.top=y;
  72.     else if(y>TrashRect.bottom) TrashRect.bottom=y; 
  73. }
  74.  
  75. void    InvalTrash()
  76. {
  77.     InsetRect(&TrashRect,-10,-10);
  78.     InvalRect(&TrashRect);
  79. }
  80. /*
  81. >>    When an output is clicked, a new wire is drawn. This routine
  82. >>    handles the drawing and updating of a rubberband wire and
  83. >>    also creates connections, when necessary.
  84. */
  85. void    RubberBandOutputWire(elem,sourcepin)
  86. Element *elem;
  87. int     sourcepin;
  88. {
  89.     int         x0,y0;
  90.     int         x1,y1;
  91.     int         pin,i,downflag;
  92.     Input        *ip;
  93.     Point        MousePoint,OldSpot;
  94.     Element     *other,*found;
  95.     int         legalconnection;
  96.     Rect        invalidator;
  97.     Rect        *inarea;
  98.     Rect        PinLite;
  99.     
  100.     PenXor();
  101.     
  102.     /*    Find out where rubberband is anchored:    */
  103.     if(elem->Type==CONN)
  104.     {    x0 = elem->Body.left+4;
  105.         y0 = elem->Body.top+4;
  106.     }
  107.     else
  108.     {    x0 = elem->OutRect.left+8;
  109.         y0 = elem->OutRect.top+8+16*sourcepin;
  110.     }
  111.     
  112.     /*    Start with a line stub.                 */
  113.     x1 = x0;
  114.     y1 = y0;
  115.     OldSpot.h = x0;
  116.     OldSpot.v = y0;
  117.     MoveTo(x0,y0);
  118.     LineTo(x0,y0);
  119.     PinLite = NilRect;    /*    No input pins are hilited.            */
  120.     
  121.     found = 0;            /*    No input was found.                 */
  122.  
  123.     do    /*    Loop until button is released.                        */
  124.     {    downflag = GetMouseTrackEvent(&MousePoint);
  125.         
  126.         /*    Do some rounding and gridding.                        */
  127.         MousePoint.h += 4;
  128.         MousePoint.v += 4;
  129.         MousePoint.h &= ~7;
  130.         MousePoint.v &= ~7;
  131.         
  132.         /*    Did mouse move?                                     */
  133.         if(MousePoint.h!=OldSpot.h || MousePoint.v !=OldSpot.v)
  134.         {    /*    It is possible to find a connection.            */
  135.             legalconnection = -1;
  136.  
  137.             /*    Undraw old line and unhilite selected pin.        */
  138.             MoveTo(x0,y0);
  139.             LineTo(x1,y1);
  140.             InvertRect(&PinLite);
  141.  
  142.             found = 0;    /*    Nothing found, yet.                 */
  143.             
  144.             /*    Is point inside edit area?                        */
  145.             if(PtInRect(MousePoint,&EditClipper))
  146.             {    i = ElemCount;    /*    Loop through elements to    */
  147.                 other = LastElem;    /* find an input pin.        */
  148.                 while(!found && i-- > 0)
  149.                 {    /*    Connector points have empty InRects.    */
  150.                     inarea = other->Type==CONN ? &other->Body : &other->InRect;
  151.                     
  152.                     if(PtInRect(MousePoint,inarea))
  153.                     {    pin = other->Type==CONN ? 0 : (MousePoint.v-other->InRect.top)/16;
  154.                         ip = (Input *)&other->Out[other->Outputs];
  155.                         
  156.                         if(ip[pin].Chip==0)
  157.                         {    found = other;
  158.                             if(other->Type==CONN)
  159.                             {    PinLite = other->Body;
  160.                                 x1 = other->Body.left+4;
  161.                                 y1 = other->Body.top+4;
  162.                             }
  163.                             else
  164.                             {    x1 = other->InRect.left;
  165.                                 y1 = other->InRect.top+8+16*pin;
  166.                                 SetRect(&PinLite,x1-1,y1-1,x1+8,y1+2);
  167.                             }
  168.                         }
  169.                         else
  170.                         {    i = -1;
  171.                             x1 = x0;
  172.                             y1 = y0;
  173.                             PinLite = NilRect;
  174.                             legalconnection = 0;
  175.                         }
  176.                     }
  177.                     /*    Check out next element. Step backwards. */
  178.                     other = (Element *)(((char *) other)-other->PrevLength);
  179.                 }
  180.                 
  181.                 /*    No input pin found? */
  182.                 if(!found && i==-1)
  183.                 {    x1 = MousePoint.h;
  184.                     y1 = MousePoint.v;
  185.                     PinLite = NilRect;
  186.                 }
  187.             }
  188.             else
  189.             {    /*    Click was outside edit area. Back to stub line. */
  190.                 x1 = x0;
  191.                 y1 = y0;
  192.                 legalconnection = 0;
  193.             }
  194.             /*    Draw new line and hilite input. */
  195.             MoveTo(x0,y0);
  196.             LineTo(x1,y1);
  197.             InvertRect(&PinLite);
  198.             OldSpot = MousePoint;
  199.         }
  200.     }    while(downflag);
  201.     
  202.     MoveTo(x0,y0);    /*    Unhilite line and pin.    */
  203.     LineTo(x1,y1);
  204.     InvertRect(&PinLite);
  205.  
  206.     if(!found && legalconnection && (x0!=x1 || y0!=y1))
  207.     {    /*    Create a connector    */
  208.         found = SimAllocate(sizeof(Element)+sizeof(Input));
  209.         InitConnector(found,MousePoint.h,MousePoint.v);
  210.         CurHeader->Last = SimEnd;
  211.         ip = (Input *)&found->Out[found->Outputs];
  212.         pin = 0;
  213.     }
  214.  
  215.     if(found)
  216.     {    /*    Connect output to input.    */
  217.         ip[pin].Chip = (char *)elem-SimBase;
  218.         ip[pin].Pin = sourcepin;
  219.         InvalRect(&found->Body);
  220.     }
  221.  
  222.     InvalLine(x0,y0,x1,y1);
  223.     PenCopy();
  224. }
  225.  
  226. typedef struct
  227. {        int x1,y1;
  228.         int x2,y2;
  229. }    wire;
  230.  
  231. /*
  232. >>    Move an element in the edit area rubberbanding input and output
  233. >>    wires and moving around a rectangular outline of the chip.
  234. */
  235. int     MoveElementAround(elem,forcedraw)
  236. Element *elem;
  237. int     forcedraw;
  238. {
  239.     wire        wires[MAX_WIRES+1],*wirep;
  240.     int         numwires;
  241.     int         i,downflag;
  242.     Element     *brother;
  243.     Input        *ip;
  244.     long        offs,ouroffset;
  245.     Rect        OldFrame;
  246.     Point        FirstPoint,OldPoint,MousePoint,OnScreen;
  247.     int         moved;
  248.     Point        offset;
  249.     
  250.     PenXor();
  251.     PenGray();
  252.  
  253.     numwires = 0;
  254.     wirep = wires;
  255.     ouroffset = (Ptr)elem-SimBase;
  256.  
  257.     SetTrashRect(&elem->Body);
  258.     
  259.     /*    Find lines connected to inputs of this chip. Easy.        */
  260.     ip = (Input *)&elem->Out[elem->Outputs];
  261.     for(i=0;i<elem->Inputs;i++)
  262.     {    if(ip->Chip != ouroffset)
  263.         if(GetConnectLine(ip,elem,i,&wirep->x1,&wirep->y1,&wirep->x2,&wirep->y2))
  264.         {    ExpandTrash(wirep->x2,wirep->y2);
  265.             if(numwires<MAX_WIRES)
  266.             {    numwires++;
  267.                 wirep++;
  268.             }
  269.         }
  270.         ip++;
  271.     }
  272.  
  273.     /*    Find lines connected to outputs of this chip. Harder.    */
  274.     for(offs=CurHeader->First;offs<CurHeader->Last;offs+=brother->Length)
  275.     {    brother=(Element *)(SimBase+offs);
  276.         ip=(Input *)&brother->Out[brother->Outputs];
  277.         if(brother!=elem)
  278.         for(i=0;i<brother->Inputs;i++)
  279.         {    if(ip->Chip == ouroffset)
  280.             {    GetConnectLine(ip,brother,i,&wirep->x2,&wirep->y2,&wirep->x1,&wirep->y1);
  281.                 ExpandTrash(wirep->x2,wirep->y2);
  282.                 if(numwires<MAX_WIRES)
  283.                 {    numwires++;
  284.                     wirep++;
  285.                 }
  286.             }
  287.             ip++;
  288.         }
  289.     }
  290.  
  291.     /*    forcedraw is true, previously undisplayed element.    */
  292.     if(forcedraw)
  293.     {    OldFrame=elem->Body;
  294.         FrameRect(&OldFrame);
  295.         
  296.         wirep=wires;
  297.         for(i=0;i<numwires;i++)
  298.         {    MoveTo(wirep->x1,wirep->y1);
  299.             LineTo(wirep->x2,wirep->y2);
  300.             wirep++;
  301.         }
  302.         moved= -1;
  303.     }
  304.     else
  305.     {    OldFrame=NilRect;
  306.         moved=0;
  307.     }
  308.  
  309.     GetMouseDownPoint(&FirstPoint);
  310.     FirstPoint.h-=4;
  311.     FirstPoint.v-=4;
  312.  
  313.     OldPoint.h=0;
  314.     OldPoint.v=0;
  315.  
  316.     do    /*    A simple rubberbanding loop. Simpler than above routine.    */
  317.     {    downflag=GetMouseTrackEvent(&MousePoint);
  318.         OnScreen=MousePoint;
  319.         MousePoint.h = (MousePoint.h - FirstPoint.h) & ~7;
  320.         MousePoint.v = (MousePoint.v - FirstPoint.v) & ~7;
  321.         if(MousePoint.h!=OldPoint.h || MousePoint.v!=OldPoint.v)
  322.         {    if(moved<0)
  323.             {    FrameRect(&OldFrame);
  324.                 wirep=wires;
  325.                 for(i=0;i<numwires;i++)
  326.                 {    MoveTo(wirep->x1+OldPoint.h,wirep->y1+OldPoint.v);
  327.                     LineTo(wirep->x2,wirep->y2);
  328.                     wirep++;
  329.                 }
  330.             }
  331.             if(PtInRect(OnScreen,&EditClipper))
  332.             {    OldFrame=elem->Body;
  333.                 OffsetRect(&OldFrame,MousePoint.h,MousePoint.v);
  334.                 FrameRect(&OldFrame);
  335.                 offset.h=MousePoint.h-OldPoint.h;
  336.                 offset.v=MousePoint.v-OldPoint.v;
  337.                 wirep=wires;
  338.                 for(i=0;i<numwires;i++)
  339.                 {    MoveTo(wirep->x1+MousePoint.h,wirep->y1+MousePoint.v);
  340.                     LineTo(wirep->x2,wirep->y2);
  341.                     wirep++;
  342.                 }
  343.                 moved= -1;
  344.             }
  345.             else
  346.             {    moved=1;    /*    Moved outside edit area, snap back. */
  347.             }
  348.             OldPoint=MousePoint;
  349.         }
  350.     }    while(downflag);
  351.     
  352.     if(moved<0)             /*    Is destination of move valid?        */
  353.     {    FrameRect(&OldFrame);
  354.         wirep=wires;
  355.         for(i=0;i<numwires;i++)
  356.         {    MoveTo(wirep->x1+OldPoint.h,wirep->y1+OldPoint.v);
  357.             LineTo(wirep->x2,wirep->y2);
  358.             wirep++;
  359.         }
  360.         if(OldPoint.h || OldPoint.v)
  361.         {    /*    Move element and force a redraw.                    */
  362.             OffsetRect(&elem->Body,OldPoint.h,OldPoint.v);
  363.             OffsetRect(&elem->InRect,OldPoint.h,OldPoint.v);
  364.             OffsetRect(&elem->OutRect,OldPoint.h,OldPoint.v);
  365.             ExpandTrash(elem->Body.left,elem->Body.top);
  366.             ExpandTrash(elem->Body.right,elem->Body.bottom);
  367.             InvalTrash();
  368.         }
  369.     }
  370.     PenCopy();
  371.     PenBlack();
  372.     
  373.     return    moved;
  374. }
  375.  
  376. /*
  377. >>    This routine finds out what to do when the user click with the
  378. >>    arrow tool.
  379. */
  380. void    DoArrowTool()
  381. {
  382.     Element     *elem,*found;
  383.     long        offs,elemsize;
  384.     int         i,j,foundpart;
  385.     Input        *ip;
  386.     Point        spot;
  387.     Rect        Eraser;
  388.  
  389.     ClipEditArea();
  390.     
  391.     GetMouseDownPoint(&spot);
  392.     
  393.     /*    First, make it possible to scan element list backwards. */
  394.     elemsize=0;
  395.     ElemCount=0;
  396.     for(offs=CurHeader->First;offs<CurHeader->Last;offs+=elem->Length)
  397.     {    elem=(Element *)(SimBase+offs);
  398.         elem->PrevLength=elemsize;
  399.         elemsize=elem->Length;
  400.         ElemCount++;
  401.     }
  402.     
  403.     LastElem=elem;
  404.     found=0;
  405.     
  406.     i=ElemCount;
  407.     while(i-- && !found)                /*    Search backwards for a possible */
  408.     {    if(PtInRect(spot,&elem->Body))    /*    hit in an element.                */
  409.         {    found=elem;
  410.             if(found->Type==CONN)        /*    Connector hit?                    */
  411.             {    Rect    temp;            /*    Do we draw a new line or move?    */
  412.             
  413.                 temp=elem->Body;
  414.                 InsetRect(&temp,2,2);
  415.                 foundpart=PtInRect(spot,&temp) ? 2 : 1;
  416.             }
  417.             else
  418.                 foundpart=1;            /*    Move element.                    */
  419.         }
  420.         if(PtInRect(spot,&elem->OutRect))
  421.         {    found=elem;                 /*    Output was hit. Draw a new line.*/
  422.             foundpart=2;
  423.         }
  424.         elem=(Element *)(((char *) elem)-elem->PrevLength);
  425.     }
  426.  
  427.     if(found)    /*    Click was found */
  428.     {    switch(foundpart)
  429.         {    case 1: /*    Click was found within element body.    */
  430.                 switch(found->Type)
  431.                 {    case INPT:    /*    Move or flip value. */
  432.                         if(MoveElementAround(found,0)==0)
  433.                         {    found->Out[0].Data ^= 1;
  434.                             Eraser=found->Body;
  435.                             InsetRect(&Eraser,1,1);
  436.                             EraseRect(&Eraser);
  437.                             MoveTo(found->Body.left+6,found->Body.bottom-4);
  438.                             DrawChar('0'+(found->Out[0].Data & 1));
  439.                         }
  440.                         break;
  441.                     case CLOK:    /*    Move or change clock rate.    */
  442.                         if(MoveElementAround(found,0)==0)
  443.                         {    if(spot.h < found->Body.left+8)
  444.                             {    found->PrivData=(found->PrivData+1) % 10;
  445.                                 Eraser=found->Body;
  446.                                 InsetRect(&Eraser,1,1);
  447.                                 EraseRect(&Eraser);
  448.                                 MoveTo(found->Body.left+2,found->Body.bottom-3);
  449.                                 Line(6,0);
  450.                                 Line(0,-10);
  451.                                 Line(5,0);
  452.                                 MoveTo(found->Body.left+2,found->Body.bottom-4);
  453.                                 DrawChar('0'+found->PrivData);
  454.                             }
  455.                         }
  456.                         break;
  457.                     default:    /*    Just move the element.    */
  458.                         MoveElementAround(found,0);
  459.                         break;
  460.                 }
  461.                 break;
  462.             case 2: /*    Click was found within output rectangle.    */
  463.                 i=(found->Type==CONN) ? 0 : (spot.v-found->OutRect.top)/16;
  464.                 RubberBandOutputWire(found,i);
  465.                 break;
  466.         }
  467.     }
  468.     else    /*    Split wire into two with a new connector point. */
  469.     {    int     x1,y1,x2,y2;
  470.         Input    *ip2;
  471.     
  472.         i=ElemCount;
  473.         elem=LastElem;
  474.         found=0;
  475.         while(i-- && !found)    /*    First find if a line was really hit.    */
  476.         {    ip=(Input *)&elem->Out[elem->Outputs];
  477.             for(j=0;j<elem->Inputs;j++)
  478.             {    if(GetConnectLine(ip,elem,j,&x1,&y1,&x2,&y2))
  479.                 if(PntOnLine(x1,y1,
  480.                              x2,y2,
  481.                              spot.h,spot.v)==2)
  482.                 {    found=SimAllocate(sizeof(Element)+sizeof(Input));
  483.                     InitConnector(found,(spot.h+4) & ~7,(spot.v+4) & ~7);
  484.                     CurHeader->Last=SimEnd;
  485.                     
  486.                     ip2=(Input *)&found->Out[1];
  487.                     *ip2= *ip;
  488.                     ip->Chip=(char *)found-SimBase;
  489.                     ip->Pin=0;
  490.  
  491.                     switch(MoveElementAround(found,-1))
  492.                     {    case -1:    
  493.                         case  0:
  494.                             InvalLine(x1,y1,x2,y2);
  495.                             break;
  496.                         case  1:    /*    User canceled by moving outside edit area    */
  497.                             *ip= *ip2;
  498.                             CurHeader->Last=(char *)found-SimBase;
  499.                             break;
  500.                     }
  501.                     
  502.                     j=elem->Inputs; /*    Fall out of search loop.    */
  503.                     i=0;
  504.                 }
  505.                 ip++;
  506.             }
  507.             elem=(Element *)(((char *) elem)-elem->PrevLength);
  508.         }
  509.     }
  510.     RestoreClipping();
  511. }
  512.